package org.bjf.modules.user.web.controller;

import com.fasterxml.jackson.annotation.JsonProperty;
import io.jsonwebtoken.Claims;
import lombok.Data;
import org.bjf.exception.CommMsgCode;
import org.bjf.exception.ServiceException;
import org.bjf.modules.user.bean.User;
import org.bjf.modules.user.enums.UserRedisKey;
import org.bjf.utils.RedisUtil;
import org.bjf.utils.TokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * jwt 登录demo示例
 *
 * jwt使用场景: 1. 一次性验证,如邮件激活帐户 2. restful api的无状态认证，客户端和服务端共享 secret，spring security oauth jwt
 */
@RestController
public class JwtLoginController {

  @Autowired
  private RedisUtil redisUtil;

  /**
   * 登录
   */
  @RequestMapping("jwt/login")
  public LoginResp login(String phone, String password) {

    // 模拟登录成功取到用户信息
    User user = new User();
    user.setUserId(555L);
    user.setUsername("zhangsan");

    return createLoginResp(user.getUserId(), user.getUsername());
  }

  /**
   * 刷新access_token
   */
  @RequestMapping("app/refresh-token")
  public LoginResp refreshToken(@RequestParam("refresh_token") String refreshToken) {
    //=== 1.校验refreshToken，取出userId
    Claims claims = TokenUtil.parseJwtToken(refreshToken);
    Long userId = (Long) claims.get("userId");
    String loginName = claims.getSubject();

    //=== 2.检查refreshToken是否黑名单
    boolean exists = redisUtil.exists(UserRedisKey.INVALID_REFRESH_TOKEN.as(refreshToken));
    if (exists) {
      throw new ServiceException(CommMsgCode.UNAUTHORIZED, "refreshToken 已经失效");
    }

    //=== 3.生成的token信息，且把旧的refreshToken放入黑名单
    LoginResp loginResp = createLoginResp(userId, loginName);
    redisUtil.setex(UserRedisKey.INVALID_REFRESH_TOKEN.as(refreshToken), refreshToken, 86400 * 100);

    return loginResp;
  }

  /**
   * 创建登录成功信息
   */
  private LoginResp createLoginResp(long userId, String loginName) {
    // 1小时
    String accessToken = TokenUtil.genJwtToken(userId, loginName, 3600);
    // 15天
    String newRefreshToken = TokenUtil.genJwtToken(userId, loginName, 86400 * 15);

    LoginResp loginResp = new LoginResp();
    loginResp.setAccessToken(accessToken);
    loginResp.setRefreshToken(newRefreshToken);
    loginResp.setExpiresIn(3600);
    return loginResp;
  }

  @Data
  public static class LoginResp {

    @JsonProperty("access_token")
    private String accessToken;
    @JsonProperty("refresh_token")
    private String refreshToken;
    @JsonProperty("expires_in")
    private long expiresIn;

  }


}
